﻿namespace MobileTrack.Web.Controllers
{
    using System;
    using System.Data.Entity;
    using System.Globalization;
    using System.Linq;
    using System.Text.RegularExpressions;
    using System.Web.Mvc;
    using System.Web.Security;
    using MobileTrack.Core;
    using MobileTrack.Core.Data;
    using MobileTrack.Core.Model;
    using MobileTrack.Web.ViewModels;

    public class AbonosController : BaseController
    {
        public AbonosController(IRepositories repositories, MembershipProvider membershipProvider, RoleProvider roleProvider)
            : base(repositories, membershipProvider, roleProvider)
        {
        }

        public ActionResult Index(string filter, long? seguimientoId)
        {
            if (seguimientoId != null)
            {
                this.ViewBag.Filter = string.Concat("Id:", seguimientoId.Value);
            }

            this.ViewBag.Filter = filter;

            var operadores = this.Repositories
                .Marcas
                .All
                .Where(m => m.EsOperador == true)
                .Select(m => m.Nombre)
                .AsEnumerable();
            this.ViewBag.OperadoresFilter = operadores;

            return this.View();
        }

        public ActionResult AddAbono()
        {
            this.LoadAllOperadores();

            if (this.Request.IsAjaxRequest())
            {
                return this.PartialView("_AddAbono");
            }

            return this.View();
        }

        [Authorize(Roles = Constants.AsocianteRole + ", " + Constants.AdministradorRole)]
        [HttpPost]
        public ActionResult AddAbono(AddAbonoViewModel newAbono)
        {
            if (this.ModelState.IsValid)
            {
                var operador = this.Repositories.Marcas.All.Single(s => s.Id == newAbono.OperadorId);

                var abono = new Abono
                {
                    Descripcion = newAbono.Descripcion,
                    Precio = newAbono.Precio,
                    FechaInicio = newAbono.FechaInicio,
                    FechaFin = newAbono.FechaFin,
                    Operador = operador
                };

                this.Repositories.Abonos.Add(abono);
                this.Repositories.SaveChanges();

                return this.Json(new { saved = true });
            }

            this.LoadAllOperadores(newAbono.OperadorId);

            return this.PartialView("_AddAbono", newAbono);
        }

        public ActionResult EditAbono()
        {
            this.LoadAllOperadores();

            if (this.Request.IsAjaxRequest())
            {
                return this.PartialView("_EditAbono");
            }

            return this.View();
        }

        [Authorize(Roles = Constants.AsocianteRole + ", " + Constants.AdministradorRole)]
        [HttpPost]
        public ActionResult EditAbono(EditAbonoViewModel editedAbono)
        {
            if (this.ModelState.IsValid)
            {
                var abono = this.Repositories.Abonos.All.Single(s => s.Id == editedAbono.Id);

                if (abono != null)
                {
                    var operador = this.Repositories.Marcas.All.Single(s => s.Id == editedAbono.OperadorId);

                    abono.Descripcion = editedAbono.Descripcion;
                    abono.Precio = editedAbono.Precio;
                    abono.Operador = operador;
                    abono.FechaInicio = editedAbono.FechaInicio;
                    abono.FechaFin = editedAbono.FechaFin;

                    this.Repositories.SaveChanges();

                    return this.Json(new { saved = true });
                }
            }

            this.LoadAllOperadores(editedAbono.OperadorId);

            return this.PartialView("_EditAbono", editedAbono);
        }

        [Authorize(Roles = Constants.AsocianteRole + ", " + Constants.AdministradorRole)]
        [HttpPost]
        public ActionResult DeleteAbono(int[] abonos)
        {
            if (abonos != null)
            {
                foreach (var abonoId in abonos)
                {
                    this.Repositories.Abonos.Delete(abonoId);
                }

                this.Repositories.SaveChanges();
            }

            return this.Json(new { deleted = true });
        }

        public ActionResult List(string filter, int page, int rows)
        {
            var query = this.Repositories
                .Abonos
                .All
                .Include(a => a.Operador)
                .Include(a => a.Ventas)
                .OrderBy(a => a.FechaInicio);

            if (!string.IsNullOrWhiteSpace(filter))
            {
                query = Filter(query, filter);
            }

            int totalRows = query.Count();
            int totalPages = (totalRows == 0) ? 1 : (int)Math.Ceiling((double)totalRows / (double)rows);
            page = (page < 1) ? 1 : page;

            var abonos = query
                .Skip((page - 1) * rows)
                .Take(rows)
                .ToArray()
                .Select(a => new AbonoViewModel(a));

            return this.Json(new { total = totalPages, page = page, records = totalRows, rows = abonos }, JsonRequestBehavior.AllowGet);
        }

        private static IOrderedQueryable<Abono> Filter(IOrderedQueryable<Abono> abonos, string filter)
        {
            var filterRegex = new Regex(@"([^\+]+):([^\+]+)\+?");
            MatchCollection fields = filterRegex.Matches(filter);
            foreach (Match m in fields)
            {
                switch (m.Groups[1].Value.ToUpperInvariant())
                {
                    case "ID":
                        long id;
                        if (long.TryParse(m.Groups[2].Value, out id))
                        {
                            abonos = abonos
                                .Where(f => f.Id == id)
                                .OrderBy(c => c.FechaInicio);
                        }

                        break;
                    case "DESCRIPCION":
                        var desc = m.Groups[2].Value;
                        abonos = abonos
                            .Where(f => f.Descripcion.Contains(desc))
                            .OrderBy(c => c.FechaInicio);

                        break;
                    case "PRECIO":
                        long precio;
                        if (long.TryParse(m.Groups[2].Value, out precio))
                        {
                            abonos = abonos
                                .Where(f => f.Precio == precio)
                                .OrderBy(c => c.FechaInicio);
                        }

                        break;
                    case "OPERADOR":
                        var oper = m.Groups[2].Value;
                        abonos = abonos
                            .Where(f => f.Operador.Nombre.Contains(oper))
                            .OrderBy(c => c.FechaInicio);

                        break;
                    case "INICIO":
                        DateTime inicio;
                        if (DateTime.TryParse(m.Groups[2].Value, out inicio))
                        {
                            abonos = abonos
                                .Where(f => f.FechaInicio == inicio)
                                .OrderBy(c => c.FechaInicio);
                        }

                        break;
                    case "FIN":
                        DateTime fin;
                        if (DateTime.TryParse(m.Groups[2].Value, out fin))
                        {
                            abonos = abonos
                                .Where(f => f.FechaFin == fin)
                                .OrderBy(c => c.FechaInicio);
                        }

                        break;

                    default:
                        break;
                }
            }

            return abonos;
        }

        private void LoadAllOperadores(long? selectedOperatorId = null)
        {
            this.ViewBag.Operadores = this.Repositories
                .Marcas
                .All
                .Where(m => m.EsOperador)
                .AsEnumerable()
                .Select(
                    s => new SelectListItem
                    {
                        Text = s.DisplayName,
                        Value = s.Id.ToString(CultureInfo.InvariantCulture),
                        Selected = selectedOperatorId.HasValue && (s.Id == selectedOperatorId.Value)
                    });
        }
    }
}
